//
//  ReactiveViewController.m
//  ReactiveObjecDemo
//
//  Created by WestWood on 2019/2/26.
//  Copyright © 2019 WestWood. All rights reserved.
//

#import "ReactiveViewController.h"
#import <ReactiveObjC/ReactiveObjC.h>

@interface ReactiveViewController ()

@property(nonatomic, strong) UILabel *label;

@property(nonatomic, strong) UILabel *lastNameLable;

@property(nonatomic, strong) UILabel *salutionLabel;

@end

@implementation ReactiveViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self.view setBackgroundColor:[UIColor whiteColor]];
    [self initialView];
    [self combineButtonClicked];
}

- (void)initialView {
    UIButton *buttonn = [[UIButton alloc] init];
    [buttonn setFrame:CGRectMake(100, 400, 150, 70)];
    [buttonn setBackgroundColor:[UIColor orangeColor]];
    [buttonn setTitle:@"racLazilyTest" forState:UIControlStateNormal];
    [self.view addSubview:buttonn];
    [buttonn addTarget:self action:@selector(racLazilyTest) forControlEvents:UIControlEventTouchUpInside];
    
    UIButton *combineButton = [[UIButton alloc] init];
    [combineButton setFrame:CGRectMake(100, 500, 150, 70)];
    [combineButton setBackgroundColor:[UIColor orangeColor]];
    [combineButton setTitle:@"racSignalContract" forState:UIControlStateNormal];
    [self.view addSubview:combineButton];
    [combineButton addTarget:self action:@selector(racSignalContract) forControlEvents:UIControlEventTouchUpInside];
    
    UIButton *mapButtonn = [[UIButton alloc] init];
    [mapButtonn setFrame:CGRectMake(100, 600, 150, 70)];
    [mapButtonn setBackgroundColor:[UIColor orangeColor]];
    [mapButtonn setTitle:@"streamSignalEffectEachSubscription" forState:UIControlStateNormal];
    [self.view addSubview:mapButtonn];
    [mapButtonn addTarget:self action:@selector(streamSignalEffectEachSubscription) forControlEvents:UIControlEventTouchUpInside];
    
    UIButton *racButton = [[UIButton alloc] init];
    [racButton setFrame:CGRectMake(100, 700, 150, 70)];
    [racButton setBackgroundColor:[UIColor orangeColor]];
    [racButton setTitle:@"Rac冷信号测试" forState:UIControlStateNormal];
    [self.view addSubview:racButton];
    [racButton addTarget:self action:@selector(addRacObeserve) forControlEvents:UIControlEventTouchUpInside];
    
    UIButton *pushButton = [[UIButton alloc] init];
    [pushButton setFrame:CGRectMake(100, 800, 150, 70)];
    [pushButton setBackgroundColor:[UIColor orangeColor]];
    [pushButton setTitle:@"Rac冷信号测试" forState:UIControlStateNormal];
    [self.view addSubview:pushButton];
    [pushButton addTarget:self action:@selector(popTo) forControlEvents:UIControlEventTouchUpInside];
}


- (void)buttonClicked {
    RACSubject *letters = [RACSubject subject];
    RACSubject *numbers = [RACSubject subject];
    RACSubject *signalOfSignals = [RACSubject subject];
    
    RACSignal *switched = [signalOfSignals switchToLatest];
    [switched subscribeNext:^(NSString *x) {
        NSLog(@"%@", x);
    }];
    
    [signalOfSignals sendNext:letters];
    [letters sendNext:@"A"];
    [letters sendNext:@"B"];
    
    [signalOfSignals sendNext:numbers];
    [letters sendNext:@"C"];
    [numbers sendNext:@"1"];
    
    [signalOfSignals sendNext:letters];
    [numbers sendNext:@"2"];
    [letters sendNext:@"D"];
}

- (void)combineButtonClicked {
    NSLog(@"Test -===---==---=-");
//    combining latest values
    RACSubject *letters = [RACSubject subject];
    RACSubject *numbers = [RACSubject subject];
    
    RACSignal *combined = [RACSignal combineLatest:@[letters, numbers] reduce:^(NSString *letter, NSString *number) {
        return [letter stringByAppendingString:number];
    }];
    
    [combined subscribeNext:^(id x) {
        NSLog(@"%@", x);
    }];
    
    [letters sendNext:@"A"];
    [letters sendNext:@"B"];
    [letters sendNext:@"1"];
    [letters sendNext:@"2"];
    [letters sendNext:@"C"];
    [letters sendNext:@"3"];
}

- (void)addMapping {
//    merge 信号的合并
    RACSubject *letters = [RACSubject subject];
    RACSubject *numbers = [RACSubject subject];
    RACSignal *merged = [RACSignal merge:@[ letters, numbers ]];
    
    [merged subscribeNext:^(NSString *x) {
        NSLog(@"%@", x);
    }];
    
    [letters sendNext:@"A"];
    [letters sendNext:@"1"];
    [letters sendNext:@"B"];
    [letters sendNext:@"C"];
    [letters sendNext:@"2"];
}

- (void)addRacObeserve {
    
}

- (void)popTo {
    [self dismissViewControllerAnimated:TRUE completion:nil];
}
    
//    self.label = [[UILabel alloc] initWithFrame:CGRectMake(100, 100, 300, 100)];
//
//    [self.label setText:self.personViewModel.person.firstName];
//    [self.view addSubview:self.label];
//
//    self.lastNameLable = [[UILabel alloc] initWithFrame:CGRectMake(100, 150, 300, 100)];
//    [self.lastNameLable setText:[[self.personViewModel person] lastName]];
//    [self.view addSubview:self.lastNameLable];
//    [self.personViewModel setDelegate:self];
//
//    self.salutionLabel = [[UILabel alloc] initWithFrame:CGRectMake(100, 200, 300, 100)];
//    [self.salutionLabel setText:[[self.personViewModel person] salutation]];
//    [self.view addSubview:self.salutionLabel];
- (void)racLazilyTest {
    NSArray *strings = @[@"A", @"B", @"C"];
//    懒加载特性：
//    在sequence的值没有被调用之前，字符串的拼接实际上都是不会发生的，sequence.head将会得到结果为A_的值，访问sequence.tail.head会得到B_诸如此类。
//    这种特性从客观上避免了没必要的工作
    
    
//    副作用只会发生一次，但是RACSequence以为着我们可以将信号进行批量操作修改，然后再进行订阅的人可以收
    
    RACSequence *sequence = [strings.rac_sequence map:^id _Nullable(NSString *value) {
        NSLog(@"%@", value);
        return [value stringByAppendingString:@"_"];
    }];
    
    NSString *concatA = [sequence head];
    NSLog(@"concatA : %@", concatA);
    
    NSString *concatB = [[sequence tail] head];
    NSLog(@"concatB : %@", concatB);
    
    NSString *concatB2 = [[sequence tail] head];
    NSLog(@"concatB2 : %@", concatB2);
    
    RACSequence *derivedSequence = [sequence map:^id _Nullable(NSString *str) {
        return [@"_" stringByAppendingString:str];
    }];
    
    NSString *concatB3 = [[derivedSequence tail] head];
    NSLog(@"concatB3 : %@", concatB3);
}

- (void)racSignalContract {
    //    RACSignal: 是一个聚焦于通过订阅同步事件传送的推送驱动流
    //    副作用将会作用于每一个订阅
    __block int aNumber = 0;
    RACSignal *aSignal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        aNumber++;
        [subscriber sendNext:@(aNumber)];
        [subscriber sendCompleted];
        return nil;
    }];
    
//    如下有两个对于信号的订阅，但是虽然是两个完全相同写法的订阅d，但是信号仍然会作用两次
    [aSignal subscribeNext:^(id  _Nullable x) {
        NSLog(@"subscribeNext: %@", x);
    }];
    
    [aSignal subscribeNext:^(id  _Nullable x) {
        NSLog(@"subscribeNext: %@", x);
    }];
}

- (void)streamSignalEffectEachSubscription {
    __block int missilesToLaunch = 0;
    RACSignal *processedSignal = [[RACSignal return:@"missiles"] map:^id _Nullable(id  _Nullable x) {
        missilesToLaunch++;
        return [NSString stringWithFormat:@"will launch %d %@", missilesToLaunch, x];
    }];
    
    [processedSignal subscribeNext:^(id  _Nullable x) {
        NSLog(@"First %@", x);
    }];
    
    [processedSignal subscribeNext:^(id  _Nullable x) {
        NSLog(@"second %@", x);
    }];
}

- (void)indentStreamOprationConstently {
//    ReactiveCocoa最优实践
//    下面文章中的推荐用法，倾向于开发者保持基于Rac编写的代码可预测，可理解，优雅，然而仅供参考，最优j实践取决于具体场景。
//    1. 用描述性的声明一个信号给方法和属性
//      当一个方法和属性已经返回了一个RACSignal，可能仅仅瞥一眼是很难理解信号的语义
//      有三个关键问题可以有效解释一份声明
//       1.是否是一个热信号(已经是活跃的信号，并且会即时返回调用者) 或者是冷信号(仅仅有人在订阅的时候，信号才会处于活跃状态)
//       2.信号是否含有多个值
//       3.信号是否含有副作用
//
//      1) 没有副作用的热信号 应该声明为一个属性而不是方法，作为属性应用标明在信号订阅事件之前，是不需要初始化的，而且额外的订阅也不会改变语义，
//         通常来说信号属性通常上应该在事件命名之后( textChanged )
//      2) 没有副作用的冷信号 应该从方法中返回一个名词性的名字，一个方法的命名标明信号可能不会一直保持，暗示工作反应可能会随着信号定语即时生效，
//          如果信号发送了多个值，名词应该使用复数形式( currentModel )
//      3) 有副作用的信号 应该返回一个动词性的名字，动词表示这个这个方法并不是幂等的，因此调用必须非常小心当副作用被设计好了之后，如果信号将会发
//         送一次或多次，包括一个辅助解释的名词(loadConfigtation  fetchLatestEvents)
//
//
//    流的一致性格式
//    当流的代码量过大的时候m，它很容易变得很臃肿，并且对格式是否正确充满了疑惑，使用一致性格式高亮，来链接一个流的开始和结束，当对流使用调用一个方
//    法，没有额外的锁紧需要（Block 参数侧）
    RACStream *stream = [[RACStream alloc] init];
    RACStream *result = [stream startWith:@0];
    RACStream *result2 = [stream map:^id _Nullable(NSNumber *value) {
        return @([value integerValue] + 1);
    }];
    

}


@end
